﻿using PLCS.Domain.PLCConfigs;

using SixLabors.ImageSharp.Memory;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Volo.Abp.DependencyInjection;

namespace PLCS.PlcInteraction
{
    public class PLCReader : ITransientDependency
    {
        private static Dictionary<string, S7Client> plcReadClients;
        private readonly ILogger<PLCReader> _logger;

        public PLCReader(ILogger<PLCReader> logger)
        {
            _logger = logger;
            plcReadClients = new Dictionary<string, S7Client>();
        }

        /// <summary>
        /// 握手
        /// </summary>
        /// <param name="address"></param>
        /// <param name="db"></param>
        /// <param name="start"></param>
        /// <param name="taskId"></param>
        /// <returns></returns>
        public static bool ReadFromPlc(string address, int db, int start, DataType dataType, int size, out string value)
        {
            value = string.Empty;
            try
            {
                S7Client readClient = plcReadClients.GetOrAdd(address, x => new S7Client());
                int connectResult = 0;
                // 先判断client连接
                if (!readClient.Connected)
                    connectResult = readClient.ConnectTo(address, 0, 1);

                if (connectResult != 0)
                    return false;

                byte[] buffer = new byte[size];
                // 获取数据类型处理方法的委托
                var dataTypeHandler = PLCReader.GetDataTypeHandler(dataType);

                // 调用数据类型处理方法，获取值
                var readValue = dataTypeHandler(buffer, start, size, size);
                if (readValue == null)
                    return false;

                value = readValue.ToString();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #region 解析buffer数组

        /// <summary>
        /// 定义一个委托类型 DataTypeHandler，用于处理不同数据类型从原始字节数组中解析出数值的方法。
        /// </summary>
        /// <param name="buffer">包含要解析的数据的原始字节数组</param>
        /// <param name="startBit">要解析的数据在字节数组中的起始位</param>
        /// <param name="endBit">要解析的数据在字节数组中的结束位</param>
        /// <param name="length">要解析的数据的长度</param>
        /// <returns>解析出来的数据对象</returns>
        public delegate object DataTypeHandler(byte[] buffer, int startBit, int endBit, int length);

        /// <summary>
        /// 根据数据类型获取对应的数据类型处理方法委托，用于从原始字节流数据中获取对应的数值。
        /// </summary>
        /// <param name="dataType">需要处理的数据类型</param>
        /// <returns>返回对应数据类型的处理方法委托</returns>
        public static DataTypeHandler GetDataTypeHandler(DataType dataType)
        {
            switch (dataType)
            {
                case DataType.BOOL:
                    // 处理bool类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetBitAt(buffer, startBit, endBit) ? 1 : 0;

                case DataType.INT:
                    // 处理int类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetIntAt(buffer, startBit);

                case DataType.DINT:
                    // 处理dint类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetDIntAt(buffer, startBit);

                case DataType.UINT:
                    // 处理uint类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetUIntAt(buffer, startBit);

                case DataType.BYTE:
                    // 处理byte类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetByteAt(buffer, startBit);

                case DataType.WORD:
                    // 处理word类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetWordAt(buffer, startBit);

                case DataType.FLOAT:
                    // 处理float类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetLRealAt(buffer, startBit);

                case DataType.CHAR:
                    // 处理char类型的数据
                    return (buffer, startBit, endBit, length) => S7.GetCharsAt(buffer, startBit, length);

                default:
                    throw new Exception($"不支持的数据类型：{dataType}");
            }
        }

        #endregion 解析buffer数组
    }
}